/**
  エオルゼアカレンダー
  copyright 2014-04-17 hiro98se@gmail.com
  Apache License 2.0

  usage:
    var calendar = new EorzeaCalendar();
    var month = calendar.getMonthAlignment();
    ...

  参考 eorzeaclock.js
  eLeMeN氏 http://www5.plala.or.jp/SQR/ff14/contents/download/eorzeaclock.html
*/

/**
 * エオルゼア時間を算出するための起点日時(UNIXタイムスタンプの1970-01-01 00:00:00みたいなもん)
 * 2012-07-12 01:00:00 らしい　が、どうもおかしいので調整しちゃう
 * (本家eorzeaclock.jsにある、夏時間の-60分と計算途中の謎の+90000秒をここで加味してる)
 */
const EORZEA_CALENDAR_EPOCH = new Date(2010, 6, 13, 1, 0, 0);

/**
 * 地球時間とエオルゼア時間の比率
 * エオルゼアの1日は地球の70分
 */
const EORZEA_CALENDAR_RATIO = (24 * 60) / 70;

/**
 * 月の名称と属性をまとめたオブジェクトの配列
 */
const EORZEA_CALENDAR_MONTH = [
		{name:"星1月", alignment:"氷", oldName:"旧暦1月"},
		{name:"霊1月", alignment:"氷", oldName:"旧暦2月"},
		{name:"星2月", alignment:"水", oldName:"旧暦3月"},
		{name:"霊2月", alignment:"水", oldName:"旧暦4月"},
		{name:"星3月", alignment:"風", oldName:"旧暦5月"},
		{name:"霊3月", alignment:"風", oldName:"旧暦6月"},
		{name:"星4月", alignment:"雷", oldName:"旧暦7月"},
		{name:"霊4月", alignment:"雷", oldName:"旧暦8月"},
		{name:"星5月", alignment:"火", oldName:"旧暦9月"},
		{name:"霊5月", alignment:"火", oldName:"旧暦10月"},
		{name:"星6月", alignment:"土", oldName:"旧暦11月"},
		{name:"霊6月", alignment:"土", oldName:"旧暦12月"}
	];

// 日の属性の並び順に懸念があるのでスイッチできるようにしておく
// trueの場合は、元祖eorzeaclock準拠
var DAYOFWEEK_ORIGIN = true;

// ところで　星＝風雷火　霊＝土氷水　のソースが不明
if (DAYOFWEEK_ORIGIN) {
	/**
	 * 日の属性(曜日)をまとめたオブジェクトの配列
	 * 元祖eorzeaclockの定義をそのまま並べているが、月・刻と並び順が違うのが気になる
	 * ゲーム内で曜日を確認する手段がないので確証なし
	 */
	const EORZEA_CALENDAR_DAYOFWEEK = [
			{name:"風属日", alignment:"風"},
			{name:"雷属日", alignment:"雷"},
			{name:"火属日", alignment:"火"},
			{name:"土属日", alignment:"土"},
			{name:"氷属日", alignment:"氷"},
			{name:"水属日", alignment:"水"},
			{name:"星極日", alignment:"風雷火"},
			{name:"霊極日", alignment:"土氷水"}
		];
} else {
	/**
	 * 日の属性(曜日)をまとめたオブジェクトの配列
	 * 仮に月・刻の属性と同じ並び順にした場合はこう
	 */
	const EORZEA_CALENDAR_DAYOFWEEK = [
			{name:"氷属日", alignment:"氷"},
			{name:"水属日", alignment:"水"},
			{name:"風属日", alignment:"風"},
			{name:"雷属日", alignment:"雷"},
			{name:"火属日", alignment:"火"},
			{name:"土属日", alignment:"土"},
			{name:"星極日", alignment:"風雷火"},
			{name:"霊極日", alignment:"土氷水"}
		];
}

/**
 * 刻の属性をまとめたオブジェクトの配列
 * start属性は残り時間をカウントするために使っているのでそれ以外の目的には向かない
 * 氷の刻の開始は0時だが、土→氷に変わるときに共通の計算式で算出できるようにに24時としている
 */
const EORZEA_CALENDAR_HOUROFDAY = [
		{name:"氷の刻", alignment:"氷", start:24*3600},
		{name:"水の刻", alignment:"水", start:4*3600},
		{name:"雷の刻", alignment:"雷", start:8*3600},
		{name:"風の刻", alignment:"風", start:12*3600},
		{name:"火の刻", alignment:"火", start:16*3600},
		{name:"土の刻", alignment:"土", start:20*3600}
	];

/**
 * 属性と、出やすい(かもしれない)アートマの対応。リスト出力に使っている
 * 本来の意味のカレンダーとは無関係だけどここで定義しちゃう
 */
const EORZEA_CALENDAR_ATMAMAP = [
		{alignment:"氷", map:"東部森林",		atma:"磨羯のアートマ"},
		{alignment:"氷", map:"高地ラノシア",	atma:"宝瓶のアートマ"},
		{alignment:"水", map:"低地ラノシア",	atma:"双魚のアートマ"},
		{alignment:"水", map:"中央ラノシア",	atma:"白羊のアートマ"},
		{alignment:"風", map:"東ザナラーン",	atma:"金牛のアートマ"},
		{alignment:"風", map:"西ザナラーン",	atma:"双子のアートマ"},
		{alignment:"雷", map:"西ラノシア",	atma:"巨蟹のアートマ"},
		{alignment:"雷", map:"外地ラノシア",	atma:"獅子のアートマ"},
		{alignment:"火", map:"中央森林",		atma:"処女のアートマ"},
		{alignment:"火", map:"中央ザナラーン",	atma:"天秤のアートマ"},
		{alignment:"土", map:"南ザナラーン",	atma:"天蠍のアートマ"},
		{alignment:"土", map:"北部森林",		atma:"人馬のアートマ"}
	];

/**
 * 日本ロケール以外のPCに対応する時のために関数化しておく。
 * でもロケール違ってもそのまま動くかも
 *
 * @return 日本時間を指すDateインスタンス
 */
function getLocalTime() {
	return new Date();
}

/**
 * ここからエオルゼアカレンダーオブジェクトの定義
 * usage: new EorzeaCalendar()
 */
function EorzeaCalendar() {
	this.init();
}
/**
 * 初期化用
 */
EorzeaCalendar.prototype.init = function() {
	var d = (getLocalTime().getTime() - EORZEA_CALENDAR_EPOCH.getTime()) / 1000 * EORZEA_CALENDAR_RATIO;

	// 60(秒)で割ったあまりが秒
	this.gameSecond = (d % 60) | 0;
	d -= this.gameSecond;
	d /= 60.0;
	// 60(分)で割ったあまりが分
	this.gameMinute = (d % 60) | 0;
	d -= this.gameMinute;
	d /= 60.0;
	// 24(時)で割ったあまりが時
	this.gameHour = (d % 24) | 0;
	d -= this.gameHour;
	d /= 24.0;
	// 32(日)で割ったあまりが日(エオルゼアの1ヶ月は常に32日)
	this.gameDay = ((d % 32) | 0);
	d -= this.gameDay;
	d /= 32.0;
	// 12(月)で割ったあまりが月
	this.gameMonth = ((d % 12) | 0);
	d -= this.gameMonth;
	d /= 12.0;
	// 残りが年
	this.gameYear = d | 0;
}
/*
 * いろいろ取得系function
 */
EorzeaCalendar.prototype.getYear = function() {
	return this.gameYear;
};
/** 月(01〜12)を返す */
EorzeaCalendar.prototype.getMonth = function() {
	// 計算結果は0〜11になっているため表示は+1する
	return ("0" + (this.gameMonth + 1)).substr(-2);
};
/** 日(01〜32)を返す */
EorzeaCalendar.prototype.getDay = function() {
	// 計算結果は0〜31になっているため表示は+1する
	return ("0" + (this.gameDay + 1)).substr(-2);
};
/**  */
EorzeaCalendar.prototype.getHour = function() {
	return ("0" + this.gameHour).substr(-2);
};
EorzeaCalendar.prototype.getMinute = function() {
	return ("0" + this.gameMinute).substr(-2);
};
EorzeaCalendar.prototype.getSecond = function() {
	return ("0" + this.gameSecond).substr(-2); 
};
/**
 * 月オブジェクトを返す
 *
 * @return obj
 *            .name 表示名
 *            .alignment 属性
 *            .oldName 旧暦表示名
 */
EorzeaCalendar.prototype.getMonthAlignment = function() {
	return EORZEA_CALENDAR_MONTH[(this.gameMonth)];
};
/**
 * 曜日(日属性)オブジェクトを返す
 *
 * @return obj
 *            .name 表示名
 *            .alignment 属性
 */
EorzeaCalendar.prototype.getDayAlignment = function() {
	return EORZEA_CALENDAR_DAYOFWEEK[(this.gameDay % 8)];
};
/**
 * 時間の属性(刻属性)オブジェクトを返す
 *
 * @return obj
 *            .name 表示名
 *            .alignment 属性
 */
EorzeaCalendar.prototype.getHourAlignment = function() {
	return EORZEA_CALENDAR_HOUROFDAY[(this.gameHour / 4 | 0)];
};
/**
 * 次の属性までの残り時間を地球時間の秒数で返す
 */
EorzeaCalendar.prototype.getRemainingSeconds = function() {
	if ((this.gameHour / 4 | 0) == 5) {
		var next = EORZEA_CALENDAR_HOUROFDAY[0];
	} else {
		var next = EORZEA_CALENDAR_HOUROFDAY[(this.gameHour / 4 | 0) + 1];
	}

	var rem = next.start - (this.gameHour * 3600 + this.gameMinute * 60 + this.gameSecond);
	return (rem / EORZEA_CALENDAR_RATIO) | 0;
};
/**
 * エオルゼア日付の文字列表現 テスト以外には意味なし
 */
EorzeaCalendar.prototype.toString = function() {
	var s = "";
	//s += this.getYear() + "年 ";
	s += this.getMonthAlignment().name + "（" + this.getMonthAlignment().alignment + "/" + this.getMonthAlignment().oldName + "）";
	s += this.getDay() + "日（" + this.getDayAlignment().name + "）";
	s += this.getHour() + ":";
	s += this.getMinute() + ":";
	s += this.getSecond() + "（" + this.getHourAlignment().name + "）";

	return s;
};


// ここから下はEorzeaCalendarオブジェクトそのものの定義ではなく、
// EorzeaCalendarを使って、時計やアートマ(が出るマップ)リストを出力するサンプルです

/**
 * エオルゼア時計を出力する。1度呼び出すと1秒ごとに繰り返し呼び出される
 * 元のeorzeaclock.jsの出力と互換性はない
 * また、月例と地球時間は出力しない（出力したい人は自分で改造して）
 *
 * @param str_id 時計を表示する場所のID。このIDを持つ要素の中に時計を出力
 * @param repeat 毎秒更新する。省略した場合はtrue。1回出して終わりたい場合はfalseに
 */
function drowEorzeaClock(str_id, repeat) {
	var obj = new EorzeaCalendar();
	var h = [];
	h.push("<p id='eorzea_calendar_dateline'>");
	h.push("<span id='eorzea_calendar_year'>" + obj.getYear() + "年</span>");
	h.push("<span id='eorzea_calendar_month_name'>" + obj.getMonthAlignment().name + "</span>");
	h.push("<span id='eorzea_calendar_month_alignment'>" + obj.getMonthAlignment().alignment + "</span>");
	h.push("<span id='eorzea_calendar_month_old'>" + obj.getMonthAlignment().oldName + "</span>");
	h.push("<span id='eorzea_calendar_day'>" + obj.getDay() + "日</span>");
	h.push("<span id='eorzea_calendar_day_alignment'>" + obj.getDayAlignment().name + "</span>");
	h.push("</p>");

	h.push("<p id='eorzea_calendar_clockline'>");
	h.push("<span id='eorzea_calendar_hour'>" + obj.getHour() + "</span>");
	h.push(":");
	h.push("<span id='eorzea_calendar_minute'>" + obj.getMinute() + "</span>");
	h.push(":");
	h.push("<span id='eorzea_calendar_second'>" + obj.getSecond() + "</span>");
	h.push("<span id='eorzea_calendar_hour_alignment'>" + obj.getHourAlignment().name + "</span>");
	h.push("</p>");

	document.getElementById(str_id).innerHTML = h.join("");
	if (typeof repeat == 'undefined' || repeat) {
		setTimeout(function(){drowEorzeaClock(str_id)}, 1000);
	}
}

/**
 * 残り秒数を見やすいように分：秒に置き換えるだけ
 */
function secondsToMinutes(sec) {
	return ((sec / 60) | 0) + "分" + (sec % 60) + "秒";
}

/**
 * アートマ対応マップリスト(迷信)を出力する
 *
 * @param str_id 時計を表示する場所のID。このIDを持つ要素の中に時計を出力
 * @param repeat 毎秒更新する。省略した場合はtrue。1回出して終わりたい場合はfalseに
 */
function drowAtmaList(str_id, repeat) {
	var obj = new EorzeaCalendar();
	var h = [];

	h.push("<p id='atma_remaining'>次の属性（刻）まで あと" + secondsToMinutes(obj.getRemainingSeconds()) + "</p>");

	h.push("<table id='atma_list_table'>");
	h.push("<tr>");
	h.push("<td>属性</td>");
	h.push("<td>アートマ</td>");
	h.push("<td>マップ</td>");
	h.push("<td>ドロップ率(暫定)</td>");
	h.push("</tr>");
	for (var i = 0; i < 12; i++) {
		var m = EORZEA_CALENDAR_ATMAMAP[i];
		var s = "atma";
		var d = 0;
		if (obj.getMonthAlignment().alignment == m.alignment) {
			s += "_";
			d += 5;
		}
		if (obj.getDayAlignment().alignment.indexOf(m.alignment) > -1) { // 星極日と霊極日が複数属性もっているから
			s += "_";
			d += 5;
		}
		if (obj.getHourAlignment().alignment == m.alignment) {
			s += "_";
			d += 5;
		}
		h.push("<tr class='" + s + "'>");
		h.push("<td>" + m.alignment + "</td>");
		h.push("<td>" + m.atma + "</td>");
		h.push("<td>" + m.map + "</td>");
		h.push("<td>" + (d == 0 ? 1:d) + " ％ </td>"); // もしかしたらほんとに0％かもしれんがな？
		h.push("</tr>");
	}
	h.push("</table>");

	document.getElementById(str_id).innerHTML = h.join("");
	if (typeof repeat == 'undefined' || repeat) {
		setTimeout(function(){drowAtmaList(str_id)}, 1000);
	}
}
